#include <kernel/initcall.h>
#include <kernel/syslog.h>
#include <kernel/bus.h>
#include <drivers/uart.h>
#include <lib/eb_string.h>
#include <mm/mem.h>


static LIST_HEAD(uart_dev);
static LIST_HEAD(uart_drv);


static struct uart_device *syslog_dev = NULL;


static void uart_device_match_driver(struct uart_device* dev)
{
    struct uart_driver *find_drv = NULL;
    struct list_node *head = &uart_drv;

    list_for_each_entry(find_drv, head, struct uart_driver, entry) {
        
        if(eb_strcmp(dev->compatible, find_drv->compatible) == 0) {
            dev->driver = find_drv;

            if(find_drv->probe) {
                find_drv->probe(dev);
            }
            return;
        }
    }
}


static void uart_driver_match_device(struct uart_driver* drv)
{
    struct uart_device *find_dev = NULL;
    struct list_node *head = &uart_dev;

    list_for_each_entry(find_dev, head, struct uart_device, entry) {
        
        if(eb_strcmp(find_dev->compatible, drv->compatible) == 0) {
            find_dev->driver = drv;

            if(drv->probe) {
                drv->probe(find_dev);
            }
            return;
        }
    }
}


int uart_device_register(struct uart_device *dev)
{
    if(dev->compatible == NULL) {
        SYSLOG_INFO("compatible of device should not be NULL");
        return -1;
    }
    
    list_add_node_at_tail(&uart_dev, &dev->entry);
    uart_device_match_driver(dev);
    return 0;
}


void uart_device_unregister(struct uart_device *dev)
{
    if(dev->tx_buf) {
        kfree(dev->tx_buf);
    }

    list_del_node(&dev->entry);
}


int uart_driver_register(struct uart_driver *drv)
{
    if(drv->compatible == NULL) {
        SYSLOG_INFO("compatible of driver should not be NULL");
        return -1;
    }
    
    list_add_node_at_tail(&uart_drv, &drv->entry);
    uart_driver_match_device(drv);

    return 0;
}


void uart_driver_unregister(struct uart_driver *drv)
{
    list_del_node(&drv->entry);
}


void syslog_bind_uart_device(struct uart_device *dev)
{
    syslog_dev = dev;
}


struct uart_device* syslog_device(void)
{
    return syslog_dev;
}
